


#include <time.h>
#include "autoconfig.h"
#include "qe_time.h"



#define SECONDS_IN_MINUTE 60
#define SECONDS_IN_HOUR 3600
#define SECONDS_IN_DAY 86400
#define SECONDS_IN_YEAR 31536000
#define SECONDS_IN_LEAP_YEAR 31622400



#if defined(_WIN32)
#include <Windows.h>
qe_time_t qe_time(void)
{
    time_t s;
    time(&s);
    return (qe_time_t)s;
}

qe_time_t qe_time_ms(void)
{
    time_t s;
    SYSTEMTIME ms;

    time(&s);
    GetSystemTime(&ms);

    return (qe_time_t)(s*1000 + ms.wMilliseconds);
}

qe_time_t qe_time_us(void)
{
    double us;
    LARGE_INTEGER time;
    LARGE_INTEGER frequency;
    QueryPerformanceFrequency(&frequency);
    QueryPerformanceCounter(&time);
    us = (double)(time.QuadPart) * 1000000.0 / frequency.QuadPart;
    return (qe_time_t)us;
}

void qe_timeval_get(qe_timeval *tv)
{
    time_t s;
    SYSTEMTIME ms;
    time(&s);
    GetSystemTime(&ms);
    tv->sec = s;
    tv->usec = ms.wMilliseconds * 1000;
}

void qe_sleep(qe_time_t second)
{
    Sleep(second*1000);
}

void qe_msleep(qe_time_t ms)
{
    Sleep(ms);
}

void qe_usleep(qe_time_t usec)
{
	HANDLE timer;
	LARGE_INTEGER interval;
	interval.QuadPart = (10 * usec);

	timer = CreateWaitableTimer(NULL, TRUE, NULL);
	SetWaitableTimer(timer, &interval, 0, NULL, NULL, 0);
	WaitForSingleObject(timer, INFINITE);
	CloseHandle(timer);
}

void qe_date(qe_date_t *date)
{
    SYSTEMTIME time;
    GetLocalTime(&time);
    date->year = time.wYear;
    date->mon  = time.wMonth;
    date->day  = time.wDay;
    date->hour = time.wHour;
    date->min  = time.wMinute;
    date->sec  = time.wSecond;
}

#elif defined(__linux__)

#include <unistd.h>
#include <sys/time.h>

qe_time_t qe_time(void)
{
    time_t s;
    time(&s);
    return (qe_time_t)s;
}

qe_time_t qe_time_ms(void)
{
    struct timeval time;
    gettimeofday(&time, NULL);
    return (qe_time_t)(time.tv_sec * 1000 + time.tv_usec / 1000);
}

qe_time_t qe_time_us(void)
{
    struct timeval time;
    gettimeofday(&time, NULL);
    return (qe_time_t)(time.tv_sec * 1000000 + time.tv_usec);
}

void qe_sleep(qe_time_t second)
{
    sleep(second);
}

void qe_msleep(qe_time_t ms)
{
    usleep(ms*1000);
}

void qe_usleep(qe_time_t us)
{
    usleep(us);
}

void qe_date(qe_date_t *date)
{
    time_t ts;
    struct tm *td;
    time(&ts);
    td = localtime(&ts);
    date->year = td->tm_year + 1900;
    date->mon  = td->tm_mon + 1;
    date->day  = td->tm_mday;
    date->hour = td->tm_hour;
    date->min  = td->tm_min;
    date->sec  = td->tm_sec;
}
#else
#include <stdio.h>
qe_time_t qe_weak qe_time(void)
{
    return 0;
}

qe_time_t qe_weak qe_time_ms(void)
{
    return 0;
}

qe_time_t qe_weak qe_time_us(void)
{
    return 0;
}

void qe_weak qe_sleep(qe_time_t second)
{
}

void qe_weak qe_msleep(qe_time_t ms)
{
}

void qe_weak qe_usleep(qe_time_t ms)
{
}

void qe_weak qe_date(qe_date_t *date)
{
}

/**
 * @brief Setting sync datetime
 * @param[in] timestr: current sync time string, format YYYY-MM-DD HH:MM:SS
 */
qe_ret qe_weak qe_datetime_sync(qe_const_str timestr)
{
}

void qe_weak qe_timeval_get(qe_timeval *tv)
{
}
#endif

void qe_weak qe_time_sec_update(qe_time_t second)
{
    
}

static int is_leap_year(int year) 
{
    return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}

static int days_in_month(int month, int year) 
{
    switch (month) {
        case 1: return 31;
        case 2: return is_leap_year(year) ? 29 : 28;
        case 3: return 31;
        case 4: return 30;
        case 5: return 31;
        case 6: return 30;
        case 7: return 31;
        case 8: return 31;
        case 9: return 30;
        case 10: return 31;
        case 11: return 30;
        case 12: return 31;
        default: return 0;
    }
}

qe_time_t qe_date_to_second(qe_date_t *dt)
{
    long days = (dt->year - 1970) * 365 + (dt->year - 1969) / 4 - (dt->year - 1901) / 100 + (dt->year - 1601) / 400;
    static const int month_days[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
    for (int i = 0; i < dt->mon - 1; ++i) {
        days += month_days[i];
    }
    if (dt->mon > 2 && is_leap_year(dt->year)) {
        days++;
    }
    days += dt->day - 1;
    return (((days * 24 + dt->hour) * 60 + dt->min) * 60 + dt->sec);
}

void qe_second_to_date(qe_time_t seconds, qe_date_t *date)
{
    int year   = 1970;
    int month  = 1;
    int day    = 1;
    int hour   = 0;
    int minute = 0;
    int second = 0;

    /* calculate years */ 
    while (seconds >= (is_leap_year(year) ? SECONDS_IN_LEAP_YEAR : SECONDS_IN_YEAR)) {
        seconds -= is_leap_year(year) ? SECONDS_IN_LEAP_YEAR : SECONDS_IN_YEAR;
        year++;
    }

    /* calculate month */ 
    while (seconds >= days_in_month(month, year) * SECONDS_IN_DAY) {
        seconds -= days_in_month(month, year) * SECONDS_IN_DAY;
        month++;
    }

    /* calculate day */ 
    while (seconds >= SECONDS_IN_DAY) {
        seconds -= SECONDS_IN_DAY;
        day++;
    }

    /* calculate hour */ 
    while (seconds >= SECONDS_IN_HOUR) {
        seconds -= SECONDS_IN_HOUR;
        hour++;
    }

    /* calculate minute */
    while (seconds >= SECONDS_IN_MINUTE) {
        seconds -= SECONDS_IN_MINUTE;
        minute++;
    }

    second = seconds;

    date->year = year;
    date->mon  = month;
    date->day  = day;
    date->hour = hour;
    date->min  = minute;
    date->sec  = second;
}